package com.quanxiaoha.framework.biz.operationlog.aspect;

import com.quanxiaoha.framework.common.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
@Aspect
@Slf4j
public class ApiOperationLogAspect {
    /** 以自定义 @ApiOperationLog 注解为切点，凡是添加 @ApiOperationLog 的方法，都会执行环绕中的代码 */
    @Pointcut("@annotation(com.quanxiaoha.framework.biz.operationlog.aspect.ApiOperationLog)")
    public void apiOperationLog() {}
    /**
     * 环绕
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("apiOperationLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // 请求开始时间startTime
        long startTime = System.currentTimeMillis();
        // 获取被请求的类和方法className,methodName
        String methodName = joinPoint.getSignature().getName();
        String className = joinPoint.getTarget().getClass().getSimpleName();//对象-类-类名
        // 请求入参arg
        Object[] args = joinPoint.getArgs();
        // 入参转 JSON 字符串argsJsonStr toJsonStr()
        //这里忘了看了一下
        String argsJsonStr = Arrays.stream(args).map(toJsonStr()).collect(Collectors.joining(","));
        // 功能描述信息description getApiOperationLogDescription
        String description = getApiOperationLogDescription(joinPoint);
        // 打印请求相关参数 "====== 请求开始: [{}], 入参: {}, 请求类: {}, 请求方法: {} =================================== "
        //这里忘了看了一下
        log.info("====== 请求开始: [{}], 入参: {}, 请求类: {}, 请求方法: {} =================================== ",description, argsJsonStr, className, methodName);
        // 执行切点方法result
        Object result = joinPoint.proceed();
        // 执行耗时executionTime
        long executionTime  = System.currentTimeMillis()-startTime;
        // 打印出参等相关信息executionTime   "====== 请求结束: [{}], 耗时: {}ms, 出参: {} =================================== "
        log.info("====== 请求结束: [{}], 耗时: {}ms, 出参: {} ===================================" ,description,executionTime,JsonUtils.toJsonString(result));
        //return
        return result;
    }

    /**
     * 获取注解的描述信息
     * @param joinPoint
     * @return
     */
    private String getApiOperationLogDescription(ProceedingJoinPoint joinPoint) {
        // 1. 从 ProceedingJoinPoint 获取 MethodSignature  signature
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 2. 使用 MethodSignature 获取当前被注解的 Method    method
        Method method = signature.getMethod();
        // 3. 从 Method 中提取  ApiOperationLog apiOperationLog
        ApiOperationLog apiOperationLog =method.getAnnotation(ApiOperationLog.class);
        // 4. 获取 description 属性
        return apiOperationLog.description();

    }

    /**
     * 转 JSON 字符串
     * @return
     */
    private Function<Object, String> toJsonStr() {
        return JsonUtils::toJsonString;
    }

}

